import Konva from 'konva'
import { IKonvaTool } from '@/components/konvaUnits/tools/IKonvaTool'
/* eslint-disable no-restricted-syntax */
/* eslint-disable guard-for-in */
/* eslint-disable no-shadow */
/* eslint-disable no-unused-vars */
/* eslint-disable no-case-declarations */
/* eslint-disable import/prefer-default-export */
import { useStore } from '@/store/index'
import { DoorPen } from '@/components/konvaUnits/tools/door'
import { FencesPen } from '@/components/konvaUnits/tools/fences'
import { IKonvaPen } from '@/components/konvaUnits/tools/IKonvaPen'
import { RulePen } from '@/components/konvaUnits/tools/rule'
import { EraseTool } from '@/components/konvaUnits/tools/eraser'
import { FencePen } from '@/components/konvaUnits/tools/fence'
import { TextPen } from '@/components/konvaUnits/tools/text'
import KonvaUtils from '@/components/konvaUnits/utils/konvaUtils'

export enum CURSOR_ENUM {
  DEFAULT_ENUM = 'default',
  DRAW_FENCE_ENUM = 'drawFence',
  DRAW_FENCES_ENUM = 'drawFences',
  DRAW_DOOR_ENUM = 'drawDoor',
  DRAW_TEXT_ENUM = 'drawText',
  DRAG_ENUM = 'drag',
  RULE_ENUM = 'rule',
  SELECT_ENUM = 'select',
  REMOVE_ENUM = 'remove'
}

export class Panel {
  container: HTMLCanvasElement

  stage: Konva.Stage

  layer!: Konva.Layer

  backgroundLayer: Konva.Layer

  backgroundImg!: Konva.Image

  konvaPen!: IKonvaPen

  konvaTool!: IKonvaTool

  constructor(container: HTMLCanvasElement) {
    this.container = container
    const store = useStore()
    const panelWidth = window.innerWidth
    const panelHeight = window.innerHeight - 100
    this.stage = new Konva.Stage({
      container: (this.container as any).id,
      width: panelWidth,
      height: panelHeight
    })
    this.backgroundLayer = new Konva.Layer()
    this.stage.add(this.backgroundLayer)
    this.backgroundLayer.moveToBottom()

    this.stage.on('wheel', (e) => {
      e.evt.preventDefault()
      this.stage.setDraggable(false)
      const scaleBy = 1.01
      const oldScale = this.stage.scaleX()
      const mousePointTo = this.getMousePos()
      const newScale = e.evt.deltaY > 0 ? oldScale * scaleBy : oldScale / scaleBy
      this.stage.scale({ x: newScale, y: newScale })
      const newPos = {
        x: -(mousePointTo.x - (this.stage.getPointerPosition() as any).x / newScale) * newScale,
        y: -(mousePointTo.y - (this.stage.getPointerPosition() as any).y / newScale) * newScale
      }
      this.stage.position(newPos)
      // this.stage.batchDraw()
    })
    this.stage.on('contextmenu', (e) => {
      e.evt.preventDefault()
    })
  }

  getMousePos() {
    const pos = this.stage.getPointerPosition()
    const scale = this.stage.scaleX()
    return {
      x: pos.x / scale - this.stage.x() / scale,
      y: pos.y / scale - this.stage.y() / scale
    }
  }

  setBackground(image: string) {
    this.backgroundLayer.removeChildren()
    const store = useStore()
    const panelWidth = store.globalParam.width
    const panelHeight = store.globalParam.height - 100
    const background = new Image()
    let backgroundImgX = 0
    let backgroundImgY = 0
    let mouseDownX = 0
    let mouseDownY = 0
    let imageDrag = false
    background.src = image
    if (this.konvaPen) this.konvaPen.status = 'disable'
    background.onload = () => {
      const widthScale = panelWidth / background.width
      const heightScale = panelHeight / background.height
      const backgroundScale = widthScale > heightScale ? heightScale : widthScale

      const backgroundWidth = background.width * backgroundScale
      const backgroundHeight = background.height * backgroundScale
      backgroundImgX = (panelWidth - backgroundWidth) / 2
      backgroundImgY = (panelHeight - backgroundHeight) / 2
      this.konvaTool = new RulePen()

      this.backgroundLayer.add(this.konvaTool.konvaGroup)

      this.backgroundImg = new Konva.Image({
        image: background,
        width: backgroundWidth,
        height: backgroundHeight,
        x: backgroundImgX,
        y: backgroundImgY,
        opacity: 0.3
      })

      this.backgroundImg.on('mousemove', (e) => {
        e.evt.preventDefault()
        if (imageDrag) {
          this.backgroundImg.x(e.evt.clientX - mouseDownX)
          this.backgroundImg.y(e.evt.clientY - mouseDownY)
        } else {
          const mousePointTo = this.getMousePos()
          this.konvaTool.mousemove(
            [mousePointTo.x, mousePointTo.y],
            store.globalParam.plottingScale
          )
        }
      })
      this.backgroundImg.on('mousedown', (e) => {
        e.evt.preventDefault()
        if (e.evt.which === 3) {
          imageDrag = true
          mouseDownX = e.evt.clientX - e.target.attrs.x
          mouseDownY = e.evt.clientY - e.target.attrs.y
          this.stage.container().style.cursor = 'pointer'
          this.konvaTool.clean()
        } else if (e.evt.which === 1) {
          const mousePointTo = this.getMousePos()
          this.stage.container().style.cursor = 'crosshair'
          this.konvaTool.mousedown(
            [mousePointTo.x, mousePointTo.y],
            store.globalParam.plottingScale,
            e.target
          )
        }
      })
      this.backgroundImg.on('mouseup', (e) => {
        e.evt.preventDefault()
        imageDrag = false
        this.stage.container().style.cursor = 'crosshair'
      })
      this.stage.container().style.cursor = 'crosshair'
      this.backgroundLayer.add(this.backgroundImg)
      this.backgroundLayer.batchDraw()
      if (this.konvaPen !== null) this.konvaPen.status = 'disable'
    }
  }

  backgroundRotate() {
    const panelWidth = (this.container as any).offsetWidth
    const panelHeight = (this.container as any).offsetHeight
    const widthScale = panelWidth / this.backgroundImg.width()
    const heightScale = panelHeight / this.backgroundImg.height()
    const backgroundScale = widthScale > heightScale ? heightScale : widthScale

    const backgroundWidth = this.backgroundImg.width() * backgroundScale
    const backgroundHeight = this.backgroundImg.height() * backgroundScale

    this.backgroundImg.rotation((this.backgroundImg.rotation() + 90) % 360)

    switch (this.backgroundImg.rotation()) {
      case 90:
        this.backgroundImg.x((panelWidth - backgroundHeight) / 2 + this.backgroundImg.height())
        this.backgroundImg.y((panelHeight - backgroundWidth) / 2)
        break
      case 180:
        this.backgroundImg.x((panelWidth - backgroundWidth) / 2 + this.backgroundImg.width())
        this.backgroundImg.y((panelHeight - backgroundHeight) / 2 + this.backgroundImg.height())
        break
      case 270:
        this.backgroundImg.x((panelWidth - backgroundHeight) / 2)
        this.backgroundImg.y((panelHeight - backgroundWidth) / 2 + this.backgroundImg.width())
        break
      default:
        this.backgroundImg.x((panelWidth - backgroundWidth) / 2)
        this.backgroundImg.y((panelHeight - backgroundHeight) / 2)
        break
    }
  }

  updatePlottingScale(value: number) {
    if (value === 0) return
    const store = useStore()
    const length = KonvaUtils.getPositionLength(this.konvaTool.beginPos, this.konvaTool.endPos)
    store.globalParamAction.updatePlottingScale(value / length)
    // store.globalParamAction.updateBabylonScale()
    this.konvaTool.clean()
    this.cleanUpAll()
    if (this.backgroundImg) this.backgroundImg.off('mousemove mousedown mouseup')
    this.konvaPen.status = 'waiting'
  }

  startDraw(selectCallback: Function) {
    this.layer = new Konva.Layer()
    if (this.backgroundImg) this.backgroundImg.off('mousemove mousedown mouseup')
    this.stage.container().style.cursor = 'crosshair'
    this.stage.add(this.layer)
    this.layer.draw()
    this.konvaPen = new FencePen()
    this.drawListen(selectCallback)
  }

  drawListen(selectCallback: Function) {
    let layerDrag = false
    let mouseDownX = 0
    let mouseDownY = 0
    // const store = useStore()
    this.konvaPen = new FencePen()
    this.stage.on('mousemove', (e) => {
      e.evt.preventDefault()
      if (layerDrag) {
        this.stage.x(e.evt.clientX - mouseDownX)
        this.stage.y(e.evt.clientY - mouseDownY)
      } else {
        const mousePointTo = this.getMousePos()
        this.konvaPen.mousemove([mousePointTo.x, mousePointTo.y], e.target)
      }
    })
    this.stage.on('mousedown', (e) => {
      e.evt.preventDefault()
      if (e.evt.which === 3) {
        layerDrag = true
        this.konvaPen.clean()
        mouseDownX = e.evt.clientX - this.stage.x()
        mouseDownY = e.evt.clientY - this.stage.y()
        this.stage.container().style.cursor = 'pointer'
      } else {
        this.stage.container().style.cursor = 'crosshair'
        const mousePointTo = this.getMousePos()
        this.konvaPen.mousedown(this.layer, [mousePointTo.x, mousePointTo.y], e.target)
      }
    })
    this.stage.on('mouseup', (e) => {
      e.evt.preventDefault()
      if (e.evt.which === 3) {
        layerDrag = false
        this.stage.container().style.cursor = 'crosshair'
      } else {
        const mousePointTo = this.getMousePos()
        this.konvaPen.mouseup([mousePointTo.x, mousePointTo.y], e.target)
      }
    })
    this.layer.on('click', (e) => {
      e.evt.preventDefault()
      if (this.konvaPen.status !== 'disable') return
      if (selectCallback !== null) selectCallback(e.target)
      this.konvaPen.click(this.layer, e.target)
    })
    this.addLayerEvent()
  }

  addLayerEvent() {
    this.layer.on('mouseover', (e) => {
      e.evt.preventDefault()
      if (
        this.konvaPen.status === 'disable' &&
        e.target instanceof Konva.Rect &&
        e.target.attrs.id.search('rect-select') !== -1
      ) {
        e.target.strokeEnabled(true)
      }
      if (e.target instanceof Konva.Rect && e.target.attrs.id.search('pillar') !== -1) {
        e.target.fill('red')
      }
    })
    this.layer.on('mouseout', (e) => {
      e.evt.preventDefault()
      if (
        this.konvaPen.status === 'disable' &&
        e.target instanceof Konva.Rect &&
        e.target.attrs.id.search('rect-select') !== -1
      ) {
        e.target.strokeEnabled(false)
      }
      if (e.target instanceof Konva.Rect && e.target.attrs.id.search('pillar') !== -1) {
        e.target.fill('black')
      }
    })
  }

  tool(status: string) {
    if (this.konvaPen) this.konvaPen.clean()
    this.stage.container().style.cursor = 'crosshair'
    this.addLayerEvent()
    switch (status) {
      case CURSOR_ENUM.SELECT_ENUM:
        if (this.konvaPen) this.konvaPen.status = 'disable'
        this.stage.container().style.cursor = 'pointer'
        break
      case CURSOR_ENUM.REMOVE_ENUM:
        this.stage.container().style.cursor = 'pointer'
        this.konvaPen = new EraseTool()
        this.konvaPen.status = 'disable'
        break
      case CURSOR_ENUM.DRAW_FENCE_ENUM:
        this.konvaPen = new FencePen()
        this.konvaPen.status = 'waiting'
        break
      case CURSOR_ENUM.DRAW_FENCES_ENUM:
        this.konvaPen = new FencesPen()
        this.konvaPen.status = 'waiting'
        break
      case CURSOR_ENUM.DRAW_DOOR_ENUM:
        this.konvaPen = new DoorPen()
        this.konvaPen.status = 'waiting'
        break
      case CURSOR_ENUM.DRAW_TEXT_ENUM:
        this.konvaPen = new TextPen()
        this.layer.off('mouseout mouseover')
        this.konvaPen.status = 'waiting'
        break

      default:
        if (this.konvaPen) this.konvaPen.status = 'waiting'
        break
    }
  }

  drawBack(): void {
    const store = useStore()
    const history = Array.from(store.drawing.history)
    if (history.length > 0) {
      const lastOne = history[history.length - 1]
      store.drawingAction.removeHistory(lastOne[0])
      this.layer.find(`#${lastOne[0]}`)[0].remove()
    }
  }

  reset() {
    this.stage.scale({ x: 1, y: 1 })
    this.stage.position({
      x: 0,
      y: 0
    })
    this.stage.batchDraw()
  }

  zoom(scale: number) {
    const oldScale = this.stage.scaleX()
    const newScale = scale > 0 ? oldScale + 0.1 : oldScale - 0.1
    this.stage.scale({ x: newScale, y: newScale })
    // this.stage.batchDraw()
  }

  getPos() {
    return { x: this.stage.width() / 2, y: this.stage.height() / 2 }
  }

  cleanUpAll() {
    if (this.layer) {
      this.layer.removeChildren()
      this.layer.draw()
    }

    const store = useStore()
    store.drawingAction.cleanAll()
  }

  getImageData() {
    return this.stage.toDataURL({ pixelRatio: 2 })
  }
}
